package bsh.asm.acessor;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import bsh.CompilationState;
import bsh.LocalVariable;
import bsh.exception.CompilationAssertionFailed;
import bsh.exception.CompilationFailedException;
import bsh.meta.TypeWrapper;

/**
 * {@link ObjectAccessor} para uma variavel local
 * 
 * @author takeshi
 */
public class LocalObjectAccessor implements ObjectAccessor {

    private final int offset;

    private final TypeWrapper type;

    private final LocalVariable localVariable;

    /**
     * @param lv {@link LocalVariable}
     */
    public LocalObjectAccessor(LocalVariable lv) {
        this.offset = lv.getOffset();
        this.type = lv.getType();
        this.localVariable = lv;
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.asm.acessor.ObjectAccessor#loadObject(org.objectweb.asm.MethodVisitor, bsh.CompilationState)
     */
    public void loadObject(MethodVisitor visitor, CompilationState state) {
        int opcode = this.type.toASMType().getOpcode(Opcodes.ILOAD);
        visitor.visitVarInsn(opcode, this.offset);
        state.pushStack(this.type);
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.asm.acessor.ObjectAccessor#type()
     */
    public TypeWrapper type() {
        return this.type;
    }

    /**
     * {@inheritDoc}
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "<local: " + this.offset + ">";
    }

    /**
     * {@inheritDoc}
     */
    public void preStore(MethodVisitor visitor, CompilationState state) {
    }

    /**
     * {@inheritDoc}
     */
    public boolean readOnly() {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public void storeObject(MethodVisitor visitor, CompilationState state) {
        try {
            state.getUnit().getCompilerManager().coerceStackTopTo(visitor, this.type, state);
        } catch (CompilationFailedException e) {
            throw new CompilationAssertionFailed("");
        }
        int opcode = this.type.toASMType().getOpcode(Opcodes.ISTORE);
        visitor.visitVarInsn(opcode, this.offset);
        state.popStack();
    }

    /**
     * @return {@link LocalVariable}
     */
    public LocalVariable getLocalVariable() {
        return localVariable;
    }
}
